class LogMonitorAdaptive {
    constructor(container, opts = {}) {
        this.container = typeof container === 'string'
            ? document.querySelector(container)
            : container;
        if (!this.container) throw new Error('容器未找到');

        /* ========== 配置项及其含义 ========== */
        this.cfg = {
            /* --- 尺寸相关 --- */
            width: null,        // 日志容器宽度。null=100%，可填数字(px)或字符串('80%'/'20rem')
            height: null,       // 日志容器高度。null=100vh，可填数字(px)或字符串('400px'/'50vh')

            /* --- 日志条数与滚动 --- */
            maxLines: 5000,     // 最大保留日志条数，超出后自动删除最旧日志
            autoScroll: true,   // 出现新日志时是否自动滚动到底部

            /* --- 主题与外观 --- */
            theme: 'dark',      // 主题：'dark' | 'light'，控制整体配色
            fontSize: 14,       // 日志文字大小，单位 px
            wordWrap: false,    // 日志内容是否自动换行（true=换行，false=横向滚动）

            /* --- 日志内容格式 --- */
            showTimestamp: true, // 是否显示时间戳
            showLevel: true,     // 是否显示日志级别标签
            timeFormat: 'HH:mm:ss.SSS', // 时间戳格式，可自定义

            /* --- 日志级别 & 过滤 --- */
            levels: ['DEBUG', 'INFO', 'WARN', 'ERROR', 'SUCCESS', 'SYSTEM'], // 可用日志级别
            // 过滤功能基于 levels；如只想显示 info/warn，可在这里删减

            /* --- 功能开关 --- */
            enableFilter: true,      // 顶部是否显示级别过滤复选框
            enableSearch: true,      // 是否启用搜索框与高亮功能
            enableExport: true,      // 是否允许导出日志文件
            enableClear: true,       // 是否提供“清空”按钮
            enablePause: true,       // 是否提供“暂停/继续”按钮
            enableThemeToggle: true, // 是否提供“切换主题”按钮
            enableFullscreen: true,  // 是否提供“全屏”按钮
            enableFontSize: true,    // 是否提供“字体大小 +/-”按钮
            enableWordWrap: true,    // 是否提供“换行/不换行”切换按钮

            /* --- 暂停/继续 的回调函数 --- */
            onTogglePause: () => {},

            /* --- 创建完成 的回调函数 --- */
            onCreated: () => {},

            ...opts
        };

        /* 强制确保 levels 是数组，防止 forEach 报错 */
        if (!Array.isArray(this.cfg.levels)) {
            this.cfg.levels = ['INFO', 'WARN', 'ERROR'];
        }

        this.isPaused = false;
        this.isFullscreen = false;
        this.logs = [];
        this.filters = new Set();
        this.searchTerm = '';
        this.highlightIndex = -1;
        this.highlightEls = [];

        this.initDOM();
        this.bindResize();
        this.bindGlobalEvents();

        //执行回调函数
        if(this.cfg.onCreated && typeof this.cfg.onCreated === 'function'){
            this.cfg.onCreated();
        }
    }

    /* ------------------------ 初始化 ------------------------ */
    initDOM() {
        this.container.innerHTML = '';
        this.setContainerSize();   // 宽高自适应
        this.applyContainerStyle();

        // 顶部导航栏
        this.navbar = document.createElement('div');
        Object.assign(this.navbar.style, {
            display: 'flex',
            alignItems: 'center',
            padding: '8px 12px',
            backgroundColor: this.cfg.theme === 'dark' ? '#2d2d30' : '#f3f3f3',
            borderBottom: `1px solid ${this.cfg.theme === 'dark' ? '#555' : '#ccc'}`,
            gap: '10px',
            fontSize: '14px',
            flexWrap: 'wrap'
        });

        // 按钮组
        if (this.cfg.enablePause) {
            this.pauseBtn = this.createBtn('⏸ 暂停', () => this.togglePause(), {w: '72px'});
            this.navbar.appendChild(this.pauseBtn);
        }
        if (this.cfg.enableClear) {
            this.navbar.appendChild(this.createBtn('🗑 清空', () => this.clear(), {w: '72px'}));
        }
        if (this.cfg.enableExport) {
            this.navbar.appendChild(this.createBtn('💾 导出', () => this.export(), {w: '72px'}));
        }

        // 主题切换按钮
        if (this.cfg.enableThemeToggle) {
            this.themeBtn = this.createBtn(
                this.cfg.theme === 'dark' ? '☀️ 明亮' : '🌙 暗黑',
                () => this.toggleTheme(),
                {w: '80px'}
            );
            this.navbar.appendChild(this.themeBtn);
        }

        // 字体大小
        if (this.cfg.enableFontSize) {
            this.navbar.appendChild(this.createBtn('A-', () => this.changeFontSize(-1), {w: '36px'}));
            this.navbar.appendChild(this.createBtn('A+', () => this.changeFontSize(1), {w: '36px'}));
        }

        // 换行
        if (this.cfg.enableWordWrap) {
            this.wrapBtn = this.createBtn(
                this.cfg.wordWrap ? '⏎ 换行' : '⏎ 不换行',
                () => this.toggleWordWrap(),
                {w: '90px'}
            );
            this.navbar.appendChild(this.wrapBtn);
        }

        // 全屏
        if (this.cfg.enableFullscreen) {
            this.navbar.appendChild(this.createBtn('⛶ 全屏', () => this.toggleFullscreen(), {w: '72px'}));
        }

        // 过滤复选框
        if (this.cfg.enableFilter) {
            this.cfg.levels.forEach(lvl => {
                this.navbar.appendChild(this.createCheckbox(lvl));
            });
        }

        // 搜索框
        if (this.cfg.enableSearch) {
            const searchWrap = document.createElement('span');
            searchWrap.style.marginLeft = 'auto';
            searchWrap.style.display = 'flex';
            searchWrap.style.alignItems = 'center';
            searchWrap.style.gap = '4px';

            this.searchInput = document.createElement('input');
            Object.assign(this.searchInput.style, {
                padding: '6px 8px',
                fontSize: '14px',
                border: `1px solid ${this.cfg.theme === 'dark' ? '#555' : '#bbb'}`,
                borderRadius: '4px',
                backgroundColor: this.cfg.theme === 'dark' ? '#3c3c3c' : '#fff',
                color: 'inherit',
                width: '260px'
            });
            this.searchInput.placeholder = '搜索…';
            this.searchInput.oninput = () => {
                this.searchTerm = this.searchInput.value.trim();
                this.renderVisible();
            };
            searchWrap.appendChild(this.searchInput);

            ['↑', '↓'].forEach((arr, idx) => {
                searchWrap.appendChild(
                    this.createBtn(arr, () => this.navigateHighlight(idx), {w: '30px'})
                );
            });
            this.navbar.appendChild(searchWrap);
        }

        // 日志视窗
        this.viewport = document.createElement('div');
        this.applyViewportStyle();
        this.container.appendChild(this.navbar);
        this.container.appendChild(this.viewport);

        this.renderVisible();
    }

    /* ------------------------ 样式 ------------------------ */
    setContainerSize() {
        // 如果用户未指定宽高，则自适应
        if (this.cfg.width === null) {
            this.container.style.width = '100%';
        } else {
            this.container.style.width = typeof this.cfg.width === 'number' ? `${this.cfg.width}px` : this.cfg.width;
        }

        if (this.cfg.height === null) {
            //this.container.style.height = '100vh';
            const bodyMargin = parseFloat(getComputedStyle(document.body).marginTop || 0) +
                parseFloat(getComputedStyle(document.body).marginBottom || 0);
            this.container.style.height = `calc(100vh - ${bodyMargin}px - 2px)`;
        } else {
            this.container.style.height = typeof this.cfg.height === 'number' ? `${this.cfg.height}px` : this.cfg.height;
        }
    }

    applyContainerStyle() {
        Object.assign(this.container.style, {
            display: 'flex',
            flexDirection: 'column',
            border: `1px solid ${this.cfg.theme === 'dark' ? '#444' : '#ccc'}`,
            borderRadius: '6px',
            fontFamily: 'Consolas, "Courier New", monospace',
            fontSize: `${this.cfg.fontSize}px`,
            lineHeight: 1.45,
            backgroundColor: this.cfg.theme === 'dark' ? '#1e1e1e' : '#fafafa',
            color: this.cfg.theme === 'dark' ? '#d4d4d4' : '#222',
            overflow: 'hidden'
        });
    }

    applyViewportStyle() {
        Object.assign(this.viewport.style, {
            flex: 1,
            overflowY: 'auto',
            padding: '8px',
            whiteSpace: this.cfg.wordWrap ? 'pre-wrap' : 'pre',
            wordBreak: 'break-word'
        });
    }

    /* ------------------------ 工具 ------------------------ */
    createBtn(text, handler, {w} = {}) {
        const btn = document.createElement('button');
        btn.textContent = text;
        Object.assign(btn.style, {
            padding: '6px 10px',
            fontSize: '14px',
            backgroundColor: this.cfg.theme === 'dark' ? '#444' : '#e7e7e7',
            color: 'inherit',
            border: `1px solid ${this.cfg.theme === 'dark' ? '#666' : '#ccc'}`,
            borderRadius: '4px',
            cursor: 'pointer',
            minWidth: w || 'auto'
        });
        btn.onmouseenter = () => btn.style.backgroundColor = this.cfg.theme === 'dark' ? '#555' : '#d0d0d0';
        btn.onmouseleave = () => btn.style.backgroundColor = this.cfg.theme === 'dark' ? '#444' : '#e7e7e7';
        btn.onclick = handler;
        return btn;
    }

    createCheckbox(level) {
        const lbl = document.createElement('label');
        lbl.style.color = this.cfg.theme === 'dark' ? '#ccc' : '#333';
        lbl.style.fontSize = '13px';
        lbl.style.display = 'flex';
        lbl.style.alignItems = 'center';

        const chk = document.createElement('input');
        chk.type = 'checkbox';
        chk.checked = true;
        chk.style.margin = '0 4px';
        chk.onchange = () => {
            if (chk.checked) this.filters.delete(level);
            else this.filters.add(level);
            this.renderVisible();
        };
        lbl.appendChild(chk);
        lbl.append(level.toUpperCase());
        return lbl;
    }

    /* ------------------------ 日志渲染 ------------------------ */
    log(message, level = 'info', ts = this.formatTime(new Date())) {
        if (!this.cfg.levels.includes(level)) level = 'info';
        if (this.isPaused) return;

        ts = this.cfg.showTimestamp ? ts : '';
        this.logs.push({message, level, ts, id: Date.now() + Math.random()});

        if (this.logs.length > this.cfg.maxLines) this.logs.shift();
        this.renderVisible();
    }

    renderVisible() {
        this.viewport.innerHTML = '';
        this.highlightEls = [];
        this.highlightIndex = -1;

        const filtered = this.logs.filter(l => !this.filters.has(l.level));
        const frag = document.createDocumentFragment();
        const regex = this.searchTerm ? new RegExp(`(${this.searchTerm})`, 'gi') : null;

        filtered.forEach(entry => {
            const line = document.createElement('div');
            line.style.display = 'flex';
            line.style.margin = '1px 0';

            if (this.cfg.showTimestamp && entry.ts) {
                const tsSpan = document.createElement('span');
                tsSpan.textContent = entry.ts + ' ';
                tsSpan.style.color = this.cfg.theme === 'dark' ? '#6a9955' : '#008000';
                tsSpan.style.minWidth = '90px';
                line.appendChild(tsSpan);
            }

            if (this.cfg.showLevel) {
                const lvlSpan = document.createElement('span');
                lvlSpan.textContent = `[${entry.level.toUpperCase()}]`;
                const colors = {
                    debug: '#9c27b0', info: '#2196f3', warn: '#ff9800',
                    error: '#f44336', success: '#4caf50', system: '#00bcd4'
                };
                lvlSpan.style.color = colors[entry.level.toLowerCase()] || colors.info;
                lvlSpan.style.minWidth = '70px';
                lvlSpan.style.fontWeight = 'bold';
                line.appendChild(lvlSpan);
            }

            const msgSpan = document.createElement('span');
            msgSpan.style.flex = 1;
            let msg = entry.message;
            if (regex) {
                if (regex.test(entry.message)) {
                    line.style.backgroundColor = 'rgba(255,235,59,0.25)';
                    this.highlightEls.push(line);
                }
                msg = entry.message.replace(regex, '<mark style="background:#ffeb3b;color:#000;">$1</mark>');
            }
            msgSpan.innerHTML = msg;
            line.appendChild(msgSpan);
            frag.appendChild(line);
        });

        this.viewport.appendChild(frag);
        if (this.cfg.autoScroll && !this.isPaused) {
            this.viewport.scrollTop = this.viewport.scrollHeight;
        }
    }

    /* ------------------------ 交互 ------------------------ */
    togglePause() {
        this.isPaused = !this.isPaused;
        this.pauseBtn.textContent = this.isPaused ? '▶ 继续' : '⏸ 暂停';
        this.pauseBtn.style.backgroundColor = this.isPaused
            ? (this.cfg.theme === 'dark' ? '#d32f2f' : '#ff5252')
            : (this.cfg.theme === 'dark' ? '#444' : '#e7e7e7');
        //执行回调函数
        if(this.cfg.onTogglePause && typeof this.cfg.onTogglePause === 'function'){
            this.cfg.onTogglePause(this.isPaused);
        }
    }

    toggleTheme() {
        this.cfg.theme = this.cfg.theme === 'dark' ? 'light' : 'dark';
        this.themeBtn.textContent = this.cfg.theme === 'dark' ? '☀️ 明亮' : '🌙 暗黑';
        this.applyContainerStyle();
        this.navbar.style.backgroundColor = this.cfg.theme === 'dark' ? '#2d2d30' : '#f3f3f3';
        this.renderVisible();
    }

    changeFontSize(delta) {
        this.cfg.fontSize = Math.max(10, Math.min(24, this.cfg.fontSize + delta));
        this.container.style.fontSize = `${this.cfg.fontSize}px`;
    }

    toggleWordWrap() {
        this.cfg.wordWrap = !this.cfg.wordWrap;
        this.wrapBtn.textContent = this.cfg.wordWrap ? '⏎ 不换行' : '⏎ 换行';
        this.applyViewportStyle();
    }

    toggleFullscreen() {
        if (!this.isFullscreen) {
            if (this.container.requestFullscreen) this.container.requestFullscreen();
            else if (this.container.webkitRequestFullscreen) this.container.webkitRequestFullscreen();
            else if (this.container.msRequestFullscreen) this.container.msRequestFullscreen();
        } else {
            if (document.exitFullscreen) document.exitFullscreen();
            else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
            else if (document.msExitFullscreen) document.msExitFullscreen();
        }
        this.isFullscreen = !this.isFullscreen;
    }

    navigateHighlight(dir) {
        if (!this.highlightEls.length) return;
        this.highlightIndex = (this.highlightIndex + (dir === 0 ? -1 : 1) + this.highlightEls.length) % this.highlightEls.length;
        this.highlightEls.forEach((el, idx) => {
            el.style.outline = idx === this.highlightIndex ? '2px solid #ffeb3b' : 'none';
        });
        this.highlightEls[this.highlightIndex].scrollIntoView({block: 'nearest', behavior: 'smooth'});
    }

    clear() {
        this.logs = [];
        this.renderVisible();
    }

    export() {
        const lines = this.logs.map(l => `${l.ts} [${l.level.toUpperCase()}] ${l.message}`);
        const blob = new Blob([lines.join('\n')], {type: 'text/plain;charset=utf-8'});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `log_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.txt`;
        a.click();
        URL.revokeObjectURL(url);
    }

    formatTime(date) {
        const t = date.toTimeString().slice(0, 8);
        const ms = String(date.getMilliseconds()).padStart(3, '0');
        return `${t}.${ms}`;
    }

    bindResize() {
        window.addEventListener('resize', () => {
            this.setContainerSize(); // 响应窗口变化
        });
    }

    bindGlobalEvents() {
        document.addEventListener('keydown', e => {
            if (e.key === 'Escape' && this.searchInput) {
                this.searchInput.value = '';
                this.searchTerm = '';
                this.renderVisible();
            }
            if (e.ctrlKey && e.key === 'k') {
                e.preventDefault();
                this.clear();
            }
        });
    }

    /* 快捷方法 */
    info(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'info', ts);
    }

    warn(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'warn', ts);
    }

    error(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'error', ts);
    }

    success(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'success', ts);
    }

    debug(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'debug', ts);
    }

    system(msg, ts = this.formatTime(new Date())) {
        this.log(msg, 'system', ts);
    }
}